package org.nepu.scr.indexrate.ratelongevity.longevity;

import cn.afterturn.easypoi.word.WordExportUtil;
import cn.afterturn.easypoi.word.entity.MyXWPFDocument;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import cn.hutool.core.lang.Validator;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.AllArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.lboot.core.domain.ResponseDTO;
import org.lboot.core.exception.BusinessException;
import org.lboot.jpa.utils.JpaDataUtil;
import org.lboot.ufs.service.UfsCtl;
import org.nepu.scr.indexrate.ratecompliance.compliance.params.ComplianceData;
import org.nepu.scr.indexrate.ratecompliance.complianceparams.ComplianceParamsData;
import org.nepu.scr.indexrate.ratelongevity.LongevityDataService;
import org.nepu.scr.indexrate.ratelongevity.LongevityMapService;
import org.nepu.scr.indexrate.ratelongevity.LongevityBuildService;
import org.nepu.scr.indexrate.ratelongevity.longevity.params.LongevityCreateParams;
import org.nepu.scr.indexrate.ratelongevity.longevity.params.LongevityData;
import org.nepu.scr.indexrate.ratelongevity.longevity.params.LongevityQueryParams;
import org.nepu.scr.indexrate.ratelongevity.longevity.params.LongevityUpdateParams;
import org.nepu.scr.indexrate.ratelongevity.longevityparams.LongevityParams;
import org.nepu.scr.indexrate.ratelongevity.longevityparams.LongevityParamsController;
import org.nepu.scr.indexrate.ratelongevity.longevityparams.LongevityParamsData;
import org.nepu.scr.indexrate.ratelongevity.longevityparams.LongevityParamsService;
import org.nepu.scr.indexrate.ratelongevity.longevityscore.LongevityScoreController;
import org.nepu.scr.indexrate.ratelongevity.longevityscore.LongevityScoreService;
import org.nepu.scr.service.AnalyseService;
import org.springframework.data.domain.Example;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.http.HttpStatus;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.persistence.criteria.Predicate;
import javax.servlet.http.HttpServletResponse;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import static org.nepu.scr.constant.InLevelConstant.*;
import static org.nepu.scr.constant.SikeConstant.*;

@Slf4j
@RestController
@RequestMapping("safe")
@AllArgsConstructor
@Api(tags="延寿评级结果管理")
public class LongevityController {

    public static String TARGET;
    LongevityService longevityService;

    LongevityParamsService paramsService;

    LongevityParamsController paramsController;

    UfsCtl ufsCtl;

    AnalyseService analyseService;

    LongevityScoreService scoreService;

    LongevityScoreController scoreController;

    LongevityMapService contentMapService;

    LongevityDataService setDataService;

    LongevityBuildService longevityBuildService;

//    @PostMapping("longevitys")
//    @ApiOperation(value = "新建指标评价结果管理")
    public ResponseDTO<Object> dataCreate(@Validated @RequestBody LongevityCreateParams params){

        if(params.getLongevityId().equals("")){
            throw new BusinessException(HttpStatus.BAD_REQUEST,"评价任务ID不能为空");
        }

        LongevityData data = new LongevityData();
        List<Longevity> dataList = longevityService.getByLongevityName(params.getLongevityId());

        if (dataList.size() > 0){
            throw new BusinessException(HttpStatus.BAD_REQUEST,"存在指标评价任务"+params.getLongevityId());
        }

        Longevity longevity = new Longevity();
        longevity.setLongevityName(params.getLongevityId());
        data.setLongevityId(params.getLongevityId());
        Longevity r = longevityService.saveOne(longevity);
        String longevityDataId = r.getId();
        longevityService.saveLongevityData(longevityDataId, data);

        paramsController.dataCreate(params);
        return ResponseDTO.succData(
                r
        );
    }



//    @DeleteMapping("longevitys/{id}")
//    @ApiOperation(value = "删除指标评价结果")
    public ResponseDTO<Object> dataDelete(@PathVariable("id") String id){
        String ri = longevityService.getOneUnwrap(id).getLongevityName();
        longevityService.deleteLongevityData(id);
        longevityService.deleteOne(id);
        List<LongevityParams> longevityParams = paramsService.getByLongevityName(ri);
        paramsController.dataDelete(longevityParams.get(0).getId());
        return ResponseDTO.succMsg("删除成功");
    }


    @PutMapping("longevitys/{longevityId}/data")
    @ApiOperation(value = "评价结果更新")
    public ResponseDTO<Object> dataUpdate(@PathVariable("longevityId") String longevityId,@Validated @RequestBody LongevityUpdateParams params){
        String scoreId = params.getScoreId();
        LongevityData data = longevityService.readLongevityData(longevityId);
//        BeanUtil.copyProperties(params,data, CopyOptions.create().setIgnoreNullValue(true).setIgnoreError(true));
        //更新参数
        LongevityParams p = new LongevityParams();
        p.setLongevityName(longevityService.getOneUnwrap(longevityId).getLongevityName());
        Example<LongevityParams> example = Example.of(p);
        List<LongevityParams> params1 = paramsService.getExample(example);
        LongevityParamsData paramsData = new LongevityParamsData();
        BeanUtil.copyProperties(params,paramsData, CopyOptions.create().setIgnoreNullValue(true).setIgnoreError(true));
        paramsController.dataUpdate(params1.get(0).getId(),paramsData);

        String input = null;
        for(int i=0;i<SOURCE.length;i++){
            if(params.getLongevityScore().containsKey(SOURCE[i])){
                input = SOURCE[i];
                break;
            }
        }
        if(Validator.isEmpty(input)){
            throw new BusinessException(HttpStatus.BAD_REQUEST,"输入源错误，无法计算");
        }

        //更新结果使用算法
        //输入原为C1x
        String inputC1x = null;
        for(int i=0;i<C1.length;i++){
            if(params.getLongevityScore().containsKey(C1[i])){
                inputC1x = C1[i];
                break;
            }
        }
        if(Validator.isNotEmpty(inputC1x)){
            TARGET = inputC1x;
            setDataService.setData(data,judgeGrade(params.getLongevityScore().get(TARGET)),TARGET);
            if(Validator.isNotEmpty(data.getC11())&&
                    Validator.isNotEmpty(data.getC12())&&
                    Validator.isNotEmpty(data.getC13())){
                String resultC1 = analyseService.analyse(scoreService.readLongevityData(scoreId).getC1(), buildMatrix("C1",data));
                setDataService.setData(data,resultC1,TARGET);
                if(Validator.isNotEmpty(data.getC1())&&
                        Validator.isNotEmpty(data.getC2())&&
                        Validator.isNotEmpty(data.getC3())&&
                        Validator.isNotEmpty(data.getC4())&&
                        Validator.isNotEmpty(data.getC5())){
                    String resultC = analyseService.analyse(scoreService.readLongevityData(scoreId).getC(), buildMatrix("C",data));
                    setDataService.setData(data,resultC,TARGET);
                }
            }
        }

        //输入原为C2x
        String inputC2x = null;
        for(int i=0;i<C2.length;i++){
            if(params.getLongevityScore().containsKey(C2[i])){
                inputC2x = C2[i];
                break;
            }
        }
        if(Validator.isNotEmpty(inputC2x)){
            TARGET = inputC2x;
            setDataService.setData(data,judgeGrade(params.getLongevityScore().get(TARGET)),TARGET);
            if(Validator.isNotEmpty(data.getC21())&&
                    Validator.isNotEmpty(data.getC22())&&
                    Validator.isNotEmpty(data.getC23())){
                String resultC2 = analyseService.analyse(scoreService.readLongevityData(scoreId).getC2(), buildMatrix("C2",data));
                setDataService.setData(data,resultC2,TARGET);
                if(Validator.isNotEmpty(data.getC1())&&
                        Validator.isNotEmpty(data.getC2())&&
                        Validator.isNotEmpty(data.getC3())&&
                        Validator.isNotEmpty(data.getC4())&&
                        Validator.isNotEmpty(data.getC5())){
                    String resultC = analyseService.analyse(scoreService.readLongevityData(scoreId).getC(), buildMatrix("C",data));
                    setDataService.setData(data,resultC,TARGET);
                }
            }
        }

        //输入原为C3x
        String inputC3x = null;
        for(int i=0;i<C3.length;i++){
            if(params.getLongevityScore().containsKey(C3[i])){
                inputC3x = C3[i];
                break;
            }
        }
        if(Validator.isNotEmpty(inputC3x)){
            TARGET = inputC3x;
            setDataService.setData(data,judgeGrade(params.getLongevityScore().get(TARGET)),TARGET);
            if(Validator.isNotEmpty(data.getC31())&&
                    Validator.isNotEmpty(data.getC32())){
                String resultC3 = analyseService.analyse(scoreService.readLongevityData(scoreId).getC3(), buildMatrix("C3",data));
                setDataService.setData(data,resultC3,TARGET);
                if(Validator.isNotEmpty(data.getC1())&&
                        Validator.isNotEmpty(data.getC2())&&
                        Validator.isNotEmpty(data.getC3())&&
                        Validator.isNotEmpty(data.getC4())&&
                        Validator.isNotEmpty(data.getC5())){
                    String resultC = analyseService.analyse(scoreService.readLongevityData(scoreId).getC(), buildMatrix("C",data));
                    setDataService.setData(data,resultC,TARGET);
                }
            }
        }

        //输入原为C41
        if(params.getLongevityScore().containsKey("C41")){
            TARGET = "C41";
            setDataService.setData(data,judgeGrade(params.getLongevityScore().get("C41")),TARGET);
            if(Validator.isNotEmpty(data.getC41())){
                String resultC4 = analyseService.analyse(scoreService.readLongevityData(scoreId).getC4(), buildMatrix("C4",data));
                setDataService.setData(data,resultC4,TARGET);
                if(Validator.isNotEmpty(data.getC1())&&
                        Validator.isNotEmpty(data.getC2())&&
                        Validator.isNotEmpty(data.getC3())&&
                        Validator.isNotEmpty(data.getC4())&&
                        Validator.isNotEmpty(data.getC5())){
                    String resultC = analyseService.analyse(scoreService.readLongevityData(scoreId).getC(), buildMatrix("C",data));
                    setDataService.setData(data,resultC,TARGET);
                }
            }
        }

        //输入原为C5x
        String inputC5x = null;
        for(int i=0;i<C5.length;i++){
            if(params.getLongevityScore().containsKey(C5[i])){
                inputC5x = C5[i];
                break;
            }
        }
        if(Validator.isNotEmpty(inputC5x)){
            TARGET = inputC5x;
            setDataService.setData(data,judgeGrade(params.getLongevityScore().get(TARGET)),TARGET);
            if(Validator.isNotEmpty(data.getC51())&&
                    Validator.isNotEmpty(data.getC52())){
                String resultC5 = analyseService.analyse(scoreService.readLongevityData(scoreId).getC5(), buildMatrix("C5",data));
                setDataService.setData(data,resultC5,TARGET);
                if(Validator.isNotEmpty(data.getC1())&&
                        Validator.isNotEmpty(data.getC2())&&
                        Validator.isNotEmpty(data.getC3())&&
                        Validator.isNotEmpty(data.getC4())&&
                        Validator.isNotEmpty(data.getC5())){
                    String resultC = analyseService.analyse(scoreService.readLongevityData(scoreId).getC(), buildMatrix("C",data));
                    setDataService.setData(data,resultC,TARGET);
                }
            }
        }


        LongevityData returnData = longevityService.saveLongevityData(longevityId, data);

        return ResponseDTO.succData(
                longevityBuildService.buildData(returnData)
        );
    }

    @GetMapping("longevitys")
    @ApiOperation(value = "指标评价结果列表")
    public ResponseDTO<Object> dataList(LongevityQueryParams params){
        Pageable pageable = JpaDataUtil.buildPageable(params);
        if (Validator.isEmpty(params.getSearchKey())){
            Longevity data = new Longevity();
            BeanUtil.copyProperties(params,data, CopyOptions.create().setIgnoreNullValue(true).setIgnoreError(true));
            Example<Longevity> example = Example.of(data);
            return ResponseDTO.succData(
                    longevityService.getAll(pageable,example)
            );
        }else {
            Specification<Longevity> spec = (root, query, cb) -> {
                List<Predicate> list = new ArrayList<>();
                Predicate p1 = cb.like(root.get("longevityId").as(String.class),"%"+params.getSearchKey()+"%");
                list.add(p1);
                Predicate[] predicates = new Predicate[list.size()];
                return cb.or(list.toArray(predicates));
            };
            return ResponseDTO.succData(
                    longevityService.getAll(pageable, spec)
            );
        }
    }

    @GetMapping("longevitys/{id}")
    @ApiOperation(value = "指标评价结果查询")
    public ResponseDTO<Object> dataQuery(@PathVariable("id") String id){
        LongevityData longevityData = longevityService.readLongevityData(id);
        return ResponseDTO.succData(
                longevityBuildService.buildData(longevityData)
        );
    }

    @GetMapping("longevitys/schemes/export")
    @ApiOperation(value = "指标评价结果导出")
    @SneakyThrows
    public void wordExport(@RequestParam("longevityDataId") String longevityDataId,@RequestParam("longevityParamsId") String longevityParamsId, @RequestParam(value = "templateFileId",required = false) String templateFileId
            , HttpServletResponse response){
        InputStream stream = ufsCtl.getFileStream(templateFileId);
        LongevityParamsData exportParamsData = paramsService.readLongevityData(longevityParamsId);
        LongevityData exportData = longevityService.readLongevityData(longevityDataId);
        XWPFDocument document = new MyXWPFDocument(stream);
        //生成文本内容Map
        Map<String, Object> contentMap = contentMapService.buildContentMap(longevityDataId,longevityParamsId,exportData,exportParamsData);

        //替换文本内容
        WordExportUtil.exportWord07(document, contentMap);

        //返回流
        response.setHeader("content-type", "application/octet-stream");
        response.setContentType("application/octet-stream;charset=UTF-8");
        /**
         * 修改导出文件名称
         */
        String encodedFileName = URLEncoder.encode(exportData.getLongevityId() + "安全评价报告.docx", StandardCharsets.UTF_8.toString());
        response.setHeader("Content-Disposition", "attachment; filename=\"" + encodedFileName + "\"; filename*=utf-8''" + encodedFileName);
//        response.setHeader("Content-Disposition", "attachment; filename=" + encodedFileName+".docx");
        OutputStream outputStream = response.getOutputStream();
        document.write(outputStream);
        outputStream.flush();

        outputStream.close();
    }


    //构建隶属度矩阵
    // A   优秀 良好 一般 较差 极差
    // A1  1    0   0   0   0
    // A2  1    0   0   0   0
    // A3  0    0   0   0   1
    // A4  0    1   0   0   0
    @SneakyThrows
    public Double[][] buildMatrix(String input, LongevityData data){

        Double[][] matrix = null;

        if(input.equals("C")){
            //构建C隶属度矩阵
            Double[][] m = new Double[C.length][GRADE];
            m[0] = buildMatrix(judgeNumber(data.getC1()));
            m[1] = buildMatrix(judgeNumber(data.getC2()));
            m[2] = buildMatrix(judgeNumber(data.getC3()));
            m[3] = buildMatrix(judgeNumber(data.getC4()));
            m[4] = buildMatrix(judgeNumber(data.getC5()));
            TARGET = "C";
            matrix=m;
        }else if (input.equals("C1")){
            //构建C1隶属度矩阵
            Double[][] m = new Double[C1.length][GRADE];
            m[0] = buildMatrix(judgeNumber(data.getC11()));
            m[1] = buildMatrix(judgeNumber(data.getC12()));
            m[2] = buildMatrix(judgeNumber(data.getC13()));
            TARGET = "C1";
            matrix=m;
        }else if (input.equals("C2")){
            //构建C2隶属度矩阵
            Double[][] m = new Double[C2.length][GRADE];
            m[0] = buildMatrix(judgeNumber(data.getC21()));
            m[1] = buildMatrix(judgeNumber(data.getC22()));
            m[2] = buildMatrix(judgeNumber(data.getC23()));
            TARGET = "C2";
            matrix=m;
        }else if (input.equals("C3")){
            //构建C3隶属度矩阵
            Double[][] m = new Double[C3.length][GRADE];
            m[0] = buildMatrix(judgeNumber(data.getC31()));
            m[1] = buildMatrix(judgeNumber(data.getC32()));
            TARGET = "C3";
            matrix=m;
        } else if (input.equals("C4")) {
            //构建C4隶属度矩阵
            Double[][] m = new Double[C4.length][GRADE];
            m[0] = buildMatrix(judgeNumber(data.getC41()));
            TARGET = "C4";
            matrix=m;
        } else if (input.equals("C5")) {
            //构建C5隶属度矩阵
            Double[][] m = new Double[C5.length][GRADE];
            m[0] = buildMatrix(judgeNumber(data.getC51()));
            m[1] = buildMatrix(judgeNumber(data.getC52()));
            TARGET = "C5";
            matrix=m;
        }else{
            throw new BusinessException(HttpStatus.BAD_REQUEST,"构建隶属度矩阵失败");
        }





        return  matrix;
    }

    //构建隶属度数组
    public static Double[] buildMatrix(Double d){
        Double[] result = {0.0,0.0,0.0,0.0,0.0};

        if(d>1.0){
            throw new BusinessException(HttpStatus.BAD_REQUEST,"输入指标比错误应大于等于0.0小于1.0");
        } else if (d >= ONE) {
            result[0] = 1.0;
        } else if (d >= TWO) {
            result[1] = 1.0;
        } else if (d >= THREE) {
            result[2] = 1.0;
        } else if (d >= FORE) {
            result[3] = 1.0;
        } else if (d >= FIVE) {
            result[4] = 1.0;
        }else {
            throw new BusinessException(HttpStatus.BAD_REQUEST,"输入指标比错误应大于等于0.0小于1.0");
        }
        return result;
    }

    @SneakyThrows
    public static Double judgeNumber (String grade){
        if(grade.equals(ONEG)){
            return ONE;
        }else if (grade.equals(TWOG)){
            return TWO;
        }else if (grade.equals(THREEG)){
            return THREE;
        }else if (grade.equals(FOREG)){
            return FORE;
        }else{
            return FIVE;
        }
    }


    //矩阵输出
    @SneakyThrows
    public static void printMatrix(Double[][] matrix){
        System.out.println("矩阵输出：");
        for (int i = 0; i < matrix.length; i++) {
            System.out.print("[");
            for (int j = 0; j < matrix[i].length; j++) {
                System.out.print(matrix[i][j]+" ");
            }
            System.out.println("]");
        }
    }

    //判断子指标是否完整
    @SneakyThrows
    public static Boolean keysToCheck (Map<String,Double> scoreMap,String[] keys){
        Boolean exist = true;
        for (String key : keys) {
            if (!scoreMap.containsKey(key)) {
                exist = false;
                break;
            }
        }
        return exist;
    }


    @SneakyThrows
    public static String judgeGrade (Double maxIndex){
        if(maxIndex>1.0){
            throw new BusinessException(HttpStatus.BAD_REQUEST,"输入指标比错误应大于等于0.0小于1.0");
        }
        if(maxIndex<0.0){
            throw new BusinessException(HttpStatus.BAD_REQUEST,"输入指标比错误应大于等于0.0小于1.0");
        }
        if(maxIndex>=ONE){
            return ONEG;
        }else if (maxIndex>=TWO){
            return TWOG;
        }else if (maxIndex>=THREE){
            return THREEG;
        }else if (maxIndex>=FORE){
            return FOREG;
        }else{
            return FIVEG;
        }
    }
}
